package com.lyw.utils;

import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgproc.*;
import static org.bytedeco.opencv.global.opencv_imgproc.cvtColor;

import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.DataBufferByte;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.javacpp.indexer.FloatIndexer;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JavaCvUtil {

  public static final Logger log = LoggerFactory.getLogger(JavaCvUtil.class);

  public static void test() {

  }

  /**
   * 获取某个颜色在游戏窗口（800 * 600）的坐标
   * 人物 22 90
   */
  public static void getPositionByColor(BufferedImage origin, String templatePath, String templatePath1) {
    //read in image default colors
    Mat sourceColor = bufferedImageToMat(origin);
    Mat sourceGrey = new Mat(sourceColor.size(), opencv_core.CV_8UC1);
    cvtColor(sourceColor, sourceGrey, opencv_imgproc.COLOR_BGR2GRAY);

    //load in template in grey
    Mat template = opencv_imgcodecs.imread(templatePath, opencv_imgcodecs.IMREAD_GRAYSCALE);//int = 0
    Mat template2 = opencv_imgcodecs.imread(templatePath1, opencv_imgcodecs.IMREAD_GRAYSCALE);//int = 0

    //Size for the result image
    Size size = new Size(sourceGrey.cols() - template.cols() + 1, sourceGrey.rows() - template.rows() + 1);
    Size size2 = new Size(sourceGrey.cols() - template2.cols() + 1, sourceGrey.rows() - template2.rows() + 1);

    Mat result = new Mat(size, opencv_core.CV_32FC1);
    Mat result2 = new Mat(size2, opencv_core.CV_32FC1);

    opencv_imgproc.matchTemplate(sourceGrey, template, result, opencv_imgproc.TM_CCORR_NORMED);
    opencv_imgproc.matchTemplate(sourceGrey, template2, result2, opencv_imgproc.TM_CCORR_NORMED);

    DoublePointer minVal = new DoublePointer();
    DoublePointer maxVal = new DoublePointer();
    Point min = new Point();
    Point max = new Point();
    opencv_core.minMaxLoc(result, minVal, maxVal, min, max, null);

    Point firstPoint = getPointsFromMatAboveThreshold(result, 0.97777777);
    Point firstPoint2 = getPointsFromMatAboveThreshold(result2, 1);

//        opencv_imgproc.rectangle(sourceColor, new Rect(firstPoint.x(),
//                firstPoint.y(), template.cols(), template.rows()), randColor(), 2, 0, 0);

//        opencv_imgproc.rectangle(sourceColor, new Rect(firstPoint2.x(),
//                firstPoint2.y(), template2.cols(), template2.rows()), randColor(), 2, 0, 0);
//        opencv_imgcodecs.imwrite("a.png", sourceColor);
//        System.out.println();
  }

  /**
   * 获取某个颜色在游戏窗口（800 * 600）的坐标
   */
  public static int[] getPositionByColor(BufferedImage origin, String templatePath) {
    //read in image default colors
    Mat sourceColor = bufferedImageToMat(origin);
    Mat sourceGrey = new Mat(sourceColor.size(), opencv_core.CV_8UC1);
    cvtColor(sourceColor, sourceGrey, opencv_imgproc.COLOR_BGR2GRAY);

    //load in template in grey
    Mat template = opencv_imgcodecs.imread(templatePath, opencv_imgcodecs.IMREAD_GRAYSCALE);//int = 0

    //Size for the result image
    Size size = new Size(sourceGrey.cols() - template.cols() + 1, sourceGrey.rows() - template.rows() + 1);
    Mat result = new Mat(size, opencv_core.CV_32FC1);
    opencv_imgproc.matchTemplate(sourceGrey, template, result, opencv_imgproc.TM_CCORR_NORMED);

    DoublePointer minVal = new DoublePointer();
    DoublePointer maxVal = new DoublePointer();
    Point min = new Point();
    Point max = new Point();
    opencv_core.minMaxLoc(result, minVal, maxVal, min, max, null);

    Point firstPoint = getPointsFromMatAboveThreshold(result, 1);

    opencv_imgproc.rectangle(sourceColor, new Rect(firstPoint.x(), firstPoint.y(), template.cols(), template.rows()), randColor(), 2, 0, 0);
    opencv_imgcodecs.imwrite("a.png", sourceColor);
    return null;
  }

  // some usefull things.
  public static Scalar randColor() {
    int b, g, r;
    b = ThreadLocalRandom.current().nextInt(0, 255 + 1);
    g = ThreadLocalRandom.current().nextInt(0, 255 + 1);
    r = ThreadLocalRandom.current().nextInt(0, 255 + 1);
    return new Scalar(b, g, r, 0);
  }

  private static int[] getFirstPointsFromMatAboveThreshold(Mat m, double t) {
    FloatIndexer indexer = m.createIndexer();
    int y, x, rows = m.rows(), cols = m.cols();
    for (y = 0; y < rows; y++) {
      for (x = 0; x < cols; x++) {
        if (indexer.get(y, x) > t) {
          return new int[]{x, y};
        }
      }
    }
    return null;
  }

  private static Point getPointsFromMatAboveThreshold(Mat m, double t) {

    FloatIndexer indexer = m.createIndexer();
    for (int y = 0; y < m.rows(); y++) {
      for (int x = 0; x < m.cols(); x++) {
        if (indexer.get(y, x) >= t) {
          return new Point(x, y);
        }
      }
    }
    return null;
  }

  private static List<int[]> getAllPointsFromMatAboveThreshold(Mat m, double t) {
    FloatIndexer indexer = m.createIndexer();

    List<int[]> matches = new ArrayList<>();
    int y, x, rows = m.rows(), cols = m.cols();
    for (y = 0; y < rows; y++) {
      for (x = 0; x < cols; x++) {
        if (indexer.get(y, x) > t) {
          matches.add(new int[]{x, y});
        }
      }
    }
    return matches;
  }


  public static Mat bufferedImageToMat(BufferedImage image) {

    BufferedImage rgb = convertToRGBFormat(image);
    Mat mat = new Mat(image.getHeight(), image.getWidth(), CV_8UC3);
    mat.data().put(((DataBufferByte) rgb.getRaster().getDataBuffer()).getData());
    cvtColor(mat, mat, COLOR_RGB2BGR); // RGB转BGR
    return mat;
  }

  /**
   * BufferedImage均转为TYPE_3BYTE_BGR，RGB格式
   *
   * @param input 未知格式BufferedImage图片
   * @return TYPE_3BYTE_BGR格式的BufferedImage图片
   */
  public static BufferedImage convertToRGBFormat(BufferedImage input) {
    if (BufferedImage.TYPE_3BYTE_BGR != input.getType()) {
      BufferedImage input_rgb = new BufferedImage(input.getWidth(), input.getHeight(),
              BufferedImage.TYPE_3BYTE_BGR);
      new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(input, input_rgb);
      return input_rgb;
    } else {
      return input;
    }
  }
}
